﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using MugenMvvmToolkit.Attributes;
using MugenMvvmToolkit.Interfaces;
using MugenMvvmToolkit.Interfaces.ViewModels;

namespace MugenMvvmToolkit.Infrastructure
{
    /// <summary>
    ///     Represents the class that provide display name of object.
    /// </summary>
    public class DisplayNameProvider : IDisplayNameProvider
    {
        #region Fields

        private static readonly Dictionary<MemberInfo, string> MembersToNames = new Dictionary<MemberInfo, string>();

        #endregion

        #region Implementation of IDisplayNameProvider

        /// <summary>
        ///     Gets a display name for the specified type using the specified member.
        /// </summary>
        /// <param name="memberInfo">The specified member.</param>
        /// <returns>
        ///     An instance of string.
        /// </returns>
        public string GetDisplayName(MemberInfo memberInfo)
        {
            Should.NotBeNull(memberInfo, "memberInfo");
            string name;
            using (DeadLockDetector.Lock(MembersToNames))
            {
                if (!MembersToNames.TryGetValue(memberInfo, out name))
                {
                    name = GetDisplayNameInternal(memberInfo);
                    MembersToNames[memberInfo] = name;
                }
            }
            return name;
        }

        #endregion

        #region Methods

        /// <summary>
        ///     Gets a display name for the specified type using the specified member.
        /// </summary>
        /// <param name="memberInfo">The specified member.</param>
        /// <returns>
        ///     An instance of string.
        /// </returns>
        protected virtual string GetDisplayNameInternal(MemberInfo memberInfo)
        {
            var nameAttribute = memberInfo.GetCustomAttributes(typeof (DisplayNameAttribute), true)
                                          .OfType<DisplayNameAttribute>()
                                          .FirstOrDefault();

            if (nameAttribute != null)
                return nameAttribute.DisplayName;

#if NETFX_CORE
            var type = memberInfo as TypeInfo;
            if (type != null && typeof(IViewModel).IsAssignableFrom(type.AsType()))
                return string.Empty;
#else
            var type = memberInfo as Type;
            if (type != null && typeof(IViewModel).IsAssignableFrom(type))
                return string.Empty;
#endif
            return memberInfo.Name;
        }

        #endregion
    }
}